截至 2016-12-06 上午 7 時第 8 屆 iT 邦幫忙各組的鐵人分別是 46、8、12、12、6 與 58 人,我們想要用一個表格來紀錄參賽的組別與鐵人數。
R 語言我們可以用 data frame 的資料結構來呈現這個資訊,使用 data.frame() 函數可以將 vectors 結合成資料框。
groups <- c("Modern Web", "DevOps", "Cloud", "Big Data", "Security", "自我挑戰組")
ironmen <- c(46, 8, 12, 12, 6, 58)
ironmen_df <- data.frame(groups, ironmen)
ironmen_df
View(ironmen_df)


如果我們希望在 Python 中也能夠使用 data frame,我們得仰賴 pandas 套件。與第五天討論的 numpy 套件一樣,由於我們的開發環境是安裝 Anaconda,所以不需要再去下載與安裝 pandas 套件,只需要在程式的上方引用即可(關於本系列文章的 Python 開發環境安裝請參考 [第 01 天] 建立開發環境與計算機應用。)
我們引用 pandas 套件之後依照使用慣例將它縮寫為 pd,最基本建立 data frame 的方式是利用 pandas 套件的 DataFrame() 方法將一個 dictionary 的資料結構轉換為 data frame(如果你對於 dictionary 資料結構感到陌生,我推薦你閱讀[[第 04 天] 資料結構 List,Tuple 與 Dictionary。)
import pandas as pd # 引用套件並縮寫為 pd
groups = ["Modern Web", "DevOps", "Cloud", "Big Data", "Security", "自我挑戰組"]
ironmen = [46, 8, 12, 12, 6, 58]
ironmen_dict = {"groups": groups,
"ironmen": ironmen
}
ironmen_df = pd.DataFrame(ironmen_dict)
print(ironmen_df) # 看看資料框的外觀
print(type(ironmen_df)) # pandas.core.frame.DataFrame

R 語言的使用者如果仍舊對於 pd.DataFrame() 的寫法覺得不習慣,這時可以與 R 語言中 package_name::function_name() 同時指定套件名稱與函數名稱的寫法做對照,瞬間會有恍然大悟的感覺。
我們回顧一下 R 語言資料結構中的 data frame,然後再研究 pandas 套件的 data frame。
如果 data frame 的變數類型相同,亦可以從 matrix 轉換。
my_mat <- matrix(1:4, nrow = 2, dimnames = list(NULL, c("col1", "col2")))
my_df <- data.frame(my_mat)
my_df

跟 list 的特性相仿,不會像 vector 與 matrix 僅限制容納單一資料類型。
groups <- c("Modern Web", "DevOps", "Cloud", "Big Data", "Security", "自我挑戰組")
ironmen <- c(46, 8, 12, 12, 6, 58)
ironmen_df <- data.frame(groups, ironmen)
sapply(ironmen_df, FUN = class) # 回傳每一個欄位的 class

R 語言透過使用中括號 [ , ] 或者 $ 可以很靈活地從 data frame 中選擇想要的元素(值,列或欄。)
groups <- c("Modern Web", "DevOps", "Cloud", "Big Data", "Security", "自我挑戰組")
ironmen <- c(46, 8, 12, 12, 6, 58)
ironmen_df <- data.frame(groups, ironmen)
ironmen_df[1, 2] # 第一列第二欄:Modern Web 組的鐵人數
ironmen_df[1, ] # 第一列:Modern Web 組的組名與鐵人數
ironmen_df[, 2] # 第二欄:各組的鐵人數
ironmen_df[, "ironmen"] # 各組的鐵人數
ironmen_df$ironmen # 各組的鐵人數

R 語言可以透過邏輯值來針對 data frame 進行觀測值的篩選。
roups <- c("Modern Web", "DevOps", "Cloud", "Big Data", "Security", "自我挑戰組")
ironmen <- c(46, 8, 12, 12, 6, 58)
ironmen_df <- data.frame(groups, ironmen)
ironmen_df[ironmen_df$ironmen > 10, ] # 選出鐵人數超過 10 的 data frame

R 語言可以透過一些函數來了解 data frame 的概觀。
dim(ironmen_df) # 回傳列數與欄數
str(ironmen_df) # 回傳結構
summary(ironmen_df) # 回傳描述性統計
head(ironmen_df, n = 3) # 回傳前三筆觀測值
tail(ironmen_df, n = 3) # 回傳後三筆觀測值
names(ironmen_df) # 回傳欄位名稱

如果 data frame 的變數類型相同,亦可以從 NumPy 的 2d array 轉換。
import numpy as np
import pandas as pd
my_2d_array = np.array([[1, 3],
[2, 4]
])
my_df = pd.DataFrame(my_2d_array, columns = ["col1", "col2"])
print(my_df)

跟 list 的特性相仿,不會像 ndarray 僅限制容納單一資料類型。
import pandas as pd
groups = ["Modern Web", "DevOps", "Cloud", "Big Data", "Security", "自我挑戰組"]
ironmen = [46, 8, 12, 12, 6, 58]
ironmen_dict = {"groups": groups,
"ironmen": ironmen
}
ironmen_df = pd.DataFrame(ironmen_dict)
print(ironmen_df.dtypes) # 欄位的變數類型

Pandas 透過使用中括號 [] 與 .iloc 可以很靈活地從 data frame 中選擇想要的元素。要注意的是 Python 在指定 0:1 時不包含 1,在指定 0:2 時不包含 2,這一點是跟 R 語言有很大的不同之處。
import pandas as pd
groups = ["Modern Web", "DevOps", "Cloud", "Big Data", "Security", "自我挑戰組"]
ironmen = [46, 8, 12, 12, 6, 58]
ironmen_dict = {"groups": groups,
"ironmen": ironmen
}
ironmen_df = pd.DataFrame(ironmen_dict)
print(ironmen_df.iloc[0:1, 1]) # 第一列第二欄:Modern Web 組的鐵人數
print("---")
print(ironmen_df.iloc[0:1,:]) # 第一列:Modern Web 組的組名與鐵人數
print("---")
print(ironmen_df.iloc[:,1]) # 第二欄:各組的鐵人數
print("---")
print(ironmen_df["ironmen"]) # 各組的鐵人數
print("---")
print(ironmen_df.ironmen) # 各組的鐵人數

最後兩行我們用了簡便的選擇語法,但是在正式環境選擇元素時仍然推薦使用最合適的 pandas 方法 .iloc 與 .loc 等。
While standard Python / Numpy expressions for selecting and setting are intuitive and come in handy for interactive work, for production code, we recommend the optimized pandas data access methods,
.at,.iat,.loc,.ilocand.ix.
Quoted from: 10 Minutes to pandas
Pandas 可以透過布林值來針對 data frame 進行觀測值的篩選。
import pandas as pd
groups = ["Modern Web", "DevOps", "Cloud", "Big Data", "Security", "自我挑戰組"]
ironmen = [46, 8, 12, 12, 6, 58]
ironmen_dict = {"groups": groups,
"ironmen": ironmen
}
ironmen_df = pd.DataFrame(ironmen_dict)
print(ironmen_df[ironmen_df.loc[:,"ironmen"] > 10]) # 選出鐵人數超過 10 的 data frame

Pandas 的 data frame 資料結構有一些方法或屬性可以幫助我們了解概觀。
import pandas as pd
groups = ["Modern Web", "DevOps", "Cloud", "Big Data", "Security", "自我挑戰組"]
ironmen = [46, 8, 12, 12, 6, 58]
ironmen_dict = {"groups": groups,
"ironmen": ironmen
}
ironmen_df = pd.DataFrame(ironmen_dict)
print(ironmen_df.shape) # 回傳列數與欄數
print("---")
print(ironmen_df.describe()) # 回傳描述性統計
print("---")
print(ironmen_df.head(3)) # 回傳前三筆觀測值
print("---")
print(ironmen_df.tail(3)) # 回傳後三筆觀測值
print("---")
print(ironmen_df.columns) # 回傳欄位名稱
print("---")
print(ironmen_df.index) # 回傳 index

截至上一個段落,我們已經對照了四種 R 語言的基本資料結構,還剩下最後一個是 R 語言的 factor,這在 pandas 中可以對照為 category。
groups <- c("Modern Web", "DevOps", "Cloud", "Big Data", "Security", "自我挑戰組")
groups_factor <- factor(groups) # 轉換為 factor
groups_factor

我們利用 pandas 套件的 Categorical() 方法轉換 list 為 pandas 的 category 資料結構。
import pandas as pd
groups_categorical = pd.Categorical(["Modern Web", "DevOps", "Cloud", "Big Data", "Security", "自我挑戰組"])
print(groups_categorical)
print("---")
print(type(groups_categorical))

R 語言使用 ordered = TRUE 與指定 levels = 參數加入 ordinal 的特性。
temperature <- c("cold", "warm", "hot")
temperature_factor <- factor(temperature, ordered = TRUE, levels = c("cold", "warm", "hot"))
temperature_factor

Pandas 使用 ordered = True 與指定 categories = 參數加入 ordinal 的特性。
import pandas as pd
temperature_list = ["cold", "warm", "hot"]
temperature_categorical = pd.Categorical(temperature_list, categories = ["cold", "warm", "hot"], ordered = True)
temperature = pd.Series(temperature_categorical)
print(temperature)

第六天我們開始使用 Python 的 pandas 套件,透過這個套件我們可以在 Python 開發環境中使用 data frame 與 category 的資料結構,並且跟 R 語言中的 data frame 及 factor 相互對照。
同步刊登於 Github:https://github.com/yaojenkuo/learn_python_for_a_r_user